#include "CTextEditor.h"
#include <QFile>
#include <QFileInfo>
#include <QCompleter>
#include <QStringListModel>
CTextEditor::CTextEditor(QWidget *parent) :
    QPlainTextEdit(parent),_completer(0)
{
    _highlighter=std::make_shared<Highlighter>();
    _zoomRange=1.0;
    nb=new NumberBar(this);
    this->document()->setDocumentMargin(10);
    connect(this,SIGNAL(textChanged()),this,SLOT(onContentChange()));
    connect(this,SIGNAL(updateRequest(QRect,int)),this,SLOT(onUpdateRequest(QRect,int)));
    connect(this,SIGNAL(cursorPositionChanged()),this,SLOT(onCursorPositionChanged()));
    QStringList keys=QStringList()<<"hello"<<"help";
    auto completer = new QCompleter(this);
    completer->setModel(new QStringListModel(keys,completer));
    completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
    completer->setCaseSensitivity(Qt::CaseInsensitive);
    completer->setWrapAround(false);
    setCompleter(completer);
}

void CTextEditor::setText(const QString &txt)
{
    _highlighter->setDocument(document());
    this->document()->setPlainText(txt);

}

void CTextEditor::setFile(const QString &file)
{
    QFileInfo info(file);
    setDocumentTitle(info.fileName());
    QFile fp(file);
    fp.open(QFile::ReadOnly);
    setText(fp.readAll());
    fp.close();
}

void CTextEditor::setCompleter(QCompleter *completer){

    if (_completer)
        QObject::disconnect(_completer, 0, this, 0);

    _completer = completer;

    if (!_completer)
        return;

    _completer->setWidget(this);
    _completer->setCompletionMode(QCompleter::PopupCompletion);
    _completer->setCaseSensitivity(Qt::CaseInsensitive);
    QObject::connect(_completer, QOverload<const QString &>::of(&QCompleter::activated),
                     this, &CTextEditor::insertCompletion);
}

void CTextEditor::onUpdateRequest(const QRect &rect, int dy)
{
    int w=fontMetrics().width(QString("==%1==").arg(blockCount()));
    setViewportMargins(w,0,0,0);
    nb->update();
}

void CTextEditor::onContentChange(){
    nb->update();
}

void CTextEditor::onCursorPositionChanged()
{
    QTextEdit::ExtraSelection es=QTextEdit::ExtraSelection();
    es.cursor=textCursor();
    es.cursor.clearSelection();
    es.format.setBackground(QColor("#c0c0c0"));
    es.format.setProperty(QTextFormat::FullWidthSelection,true);
    es.format.setFontItalic(true);
    setExtraSelections(QList<QTextEdit::ExtraSelection>()<<es);
    nb->update();
}

void CTextEditor::insertCompletion(const QString &completion){

    if (_completer->widget() != this)
        return;
    QTextCursor tc = textCursor();
    int extra = completion.length() - _completer->completionPrefix().length();
    tc.movePosition(QTextCursor::Left);
    tc.movePosition(QTextCursor::EndOfWord);
    tc.insertText(completion.right(extra));
    setTextCursor(tc);
}

void CTextEditor::keyPressEvent(QKeyEvent *e)
{
    if (_completer && _completer->popup()->isVisible()) {
        // The following keys are forwarded by the completer to the widget
        switch (e->key()) {
        case Qt::Key_Enter:
        case Qt::Key_Return:
        case Qt::Key_Escape:
        case Qt::Key_Tab:
        case Qt::Key_Backtab:
            e->ignore();
            return; // let the completer do default behavior
        default:
            break;
        }
    }

    bool isShortcut = ((e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_E); // CTRL+E
    if (!_completer || !isShortcut) // do not process the shortcut when we have a completer
        QPlainTextEdit::keyPressEvent(e);
    //! [7]

    //! [8]
    const bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier);
    if (!_completer || (ctrlOrShift && e->text().isEmpty()))
        return;

    static QString eow("~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="); // end of word
    bool hasModifier = (e->modifiers() != Qt::NoModifier) && !ctrlOrShift;

    QString completionPrefix = textUnderCursor();

    if (!isShortcut && (hasModifier || e->text().isEmpty()|| completionPrefix.length() < 3
                        || eow.contains(e->text().right(1)))) {
        _completer->popup()->hide();
        return;
    }

    if (completionPrefix != _completer->completionPrefix()) {
        _completer->setCompletionPrefix(completionPrefix);
        _completer->popup()->setCurrentIndex(_completer->completionModel()->index(0, 0));
    }
    QRect cr = cursorRect();
    cr.setWidth(_completer->popup()->sizeHintForColumn(0)
                + _completer->popup()->verticalScrollBar()->sizeHint().width());
    _completer->complete(cr); // popup it up!
    QPlainTextEdit::keyPressEvent(e);
}

void CTextEditor::focusInEvent(QFocusEvent *e)
{
    if (_completer)
        _completer->setWidget(this);
    QPlainTextEdit::focusInEvent(e);
}

void CTextEditor::resizeEvent(QResizeEvent *e)
{
    nb->resize(viewportMargins().left(),e->size().height());
}

void CTextEditor::wheelEvent(QWheelEvent *e)
{
    if(e->modifiers()&Qt::ControlModifier)
    {
        if(e->delta()>0)
            zoomIn(_zoomRange);
        else {
            zoomOut(_zoomRange);
        }

    }
    QPlainTextEdit::wheelEvent(e);
}

QString CTextEditor::textUnderCursor() const
{
    QTextCursor tc = textCursor();
    tc.select(QTextCursor::WordUnderCursor);
    return tc.selectedText();
}


